NES Rom Expansion 102
by: TFG (palacios_barreda!at!yahoo!dot!com!dot!mx)
-------------------------------------------------


+--------------+
| Introduction |
+--------------+

Welcome to the second part of my attempt to cover the basics of NES rom expansion. For this document, I decided to use 'Dig Dug'. It's a mapper 0 rom, easy to work with and perfect for our mapper hack.

+----------+
| Rom info |
+----------+

Format  - iNES
Mapper  - 0
PRG-ROM - 16K
CHR-ROM - 8K

+----------------------------+
| What mapper should I pick? |
+----------------------------+

You have quite a large list to chose from. Your decision depends on the plans for your hack. For instance, if you want to make a music hack (or just want some really good music included in your hack), your best pick would be Namcot 106 (aka Mapper 19). This mapper supports a few extra audio channels (other than the 4 supported by the NES, 5 if you count DMC.). If you want a more versatile mapper (extra PRG-ROM & CHR-ROM, to name a few features), Mapper 4 (aka MMC3) is the perfect solution.

Some mappers are harder to implement than others. For this example, I decided to use Mapper 3 (CNROM) as it has only one register and it's very easy to setup. (for a more gentle learning curve's sake).

By this point you should already have a copy of /Firebug/'s 'Comprehensive NES Mapper Document'.

+---------------------------------------------------------------------------+
|                                                                           |  
| Ŀ                                                       |
|  Mapper 3: CNROM                                                        |
|                                                        | 
|                                                                           |
| Ŀ    |
|  This mapper is used on many older U.S. and Japanese games, such as     |
|  Solomon's Key, Gradius, and Hudson's Adventure Island.                 |
|     |
|                                                                           |
| Ŀ   Ŀ      |
|  $8000  $FFFF Ĵ CCCCCCCC                                           |
|                                                |
|                                                                        |
|                                                                        |
|                          Select 8K VROM bank at PPU $0000       |
|                           |
|                                                                           | 
| Notes: - The ROM size is either 16K or 32K and is not switchable. It is   |
|          loaded in the same manner as a NROM game; in other words,        |
|           it's loaded at $8000 if it's a 32K ROM size, and at $C000 if    |
|           it's a 16K ROM size. (This is because a 6502 CPU requires       | 
|           several vectors to be at $FFFA  $FFFF, and therefore ROM needs | 
|           to be there at all times.)                                      |
|        - The first 8K VROM bank is swapped into PPU $0000 when the cart   |
|           is reset.                                                       |
|        - This is probably the simplest memory mapper and can easily be    |
|           incorporated into a NES emulator.                               |
+---------------------------------------------------------------------------+

Each mapper has one or more registers. These registers are the mapper's control panel. In this particular case, the only port avaliable is located in the $8000-$FFFF range of the CPU memory. What does that mean? Well, if you write a number (a bank number) to any address within this range, you are going to trigger the mapper's functionality.

lda #$01
sta $8000

In other words, load 8K of CHR-ROM at PPU $0000. If you aren't sure of what PPU $0000 means, you should go back and re-read Yoshi's NES documentation.

+-------------------+
| Adding the mapper |
+-------------------+

Open up a hex editor, load you iNES Dig Dug rom image and modify the mapper number (that'd be offset 06h, set it to 0x30). Refer to your iNES format document to figure out why 0x30 and not 0x03 as you expected.

As almost every other Mapper 0 rom, this game has little to none free space. The mapper we picked doesn't have PRG-ROM swapping capabilities, however, it uses only 16K of PRG-ROM; which means we can add an extra bank.

Modify the PRG-ROM flag of you iNES header (offset 04h = 0x02) and insert 0x4000 bytes at offset 10h. Test your rom.

There you go. Now you have a Mapper 3 rom with a free 16K bank of PRG-ROM waiting to be exploited.

+----------------+
| Making it work |
+----------------+

Since this mapper focuses on CHR-ROM, we'll have to add an extra 8K bank of CHR-ROM to test it. Use the CHR-ROM bank that comes with this guide or rip your own from any other game.

Insert new_gfx.chr at offset A010h and update the iNES CHR-ROM flag (offset 05h = 0x02)

We have to re-allocate some of the game's code to make our new PRG-ROM bank usable. Run your rom in FCEUd and press F1. Scroll down to $FFFA and write those 2 bytes down (0x000C) 16 bit pointers are stored backwards, so, the correct address spells: $C000. That's the CPU address of the RESET vector (refer to Yoshi's documentation to learn more about interrupts). This means that whenever the game starts or gets reset, it'll jump to that address.

We are going to add a simple 'PRESS ANY BUTTON TO CONTINUE' screen to test our new gfx.

Use x816 to assemble
--------------------

.MEM 8
.INDEX 8
.BASE $8000

new_reset:

lda #$01
sta $8000
jmp $c000

.END

--------------------

$C000 is the address for the reset vector. Since we want our hack-screen to appear before the game's title screen, a quick solution would be to redirect the game to our code in order to anticipate the title screen. Assemble and insert that code at offset 10h ($8000 in terms of CPU memory). Now, update the vector table and set the reset interrupt to $8000 (800Ch = 0x0080). Remember that the interrupt table is located at the end of the last 16K PRG-ROM bank.

Basically, the code is telling the mapper to load CHR-ROM Bank #1 into PPU $0000 (counting from 0). Refer to the mapper's chart posted earlier.

You should get a full working game with a different font and glitchy (non-font) graphics. Now, let's add our 'PRESS..' screen and make it work like it is supposed to.

I added a few comments to the code. If you have specific questions about the code, either, drop me a line or go to #consoledev at espernet.

Use x816 to assemble 
Insert at offset 10h
--------------------

.MEM 8
.INDEX 8
.BASE $8000

new_reset:

-	lda $2002
	bpl -
--	lda $2002
	bpl --

; Load chr-rom bank #1 into VRAM
	lda #$01
	sta $8000

; Turn off screen
	lda #$00
	sta $2001
	jsr clear_screen

; Write palettes
	lda #$3F
	sta $2006
	lda #$00
	sta $2006	
	ldx #$00
-	lda pal_data,x
	sta $2007
	inx
	cpx #$10
	bne -

; Write atribute table data
	ldx #$40
	lda #$23
	sta $2006
	lda #$C0
	sta $2006
	lda #$00
-	sta $2007
	dex
	bne -
		

; Write our "text"
	lda #$20
	sta $2006
	lda #$82
	sta $2006
	ldx #$00
	lda str_press,x

; Convert ASCII to our font code
; 'A' = $41 (ASCII)
; 'A' = $0A (PROPIETARY)
	
-	sec
	sbc #$37
	sta $2007
	inx
	lda str_press,x
	bne -		; if 0, exit loop
	lda #$00
	sta $2005
	sta $2005

; Turn on screen
	lda #%00001010
	sta $2001
	lda #%00010000
	sta $2000

; Read key
get_key:	
	lda #$00
	sta $4016
	lda #$01
	sta $4016
	ldy #$08
-	lda $4016
	and #$01
	bne restore_gfx
	dey
	bne -
	jmp get_key

restore_gfx:
	lda #$00
	sta $2001 ; turn off screen
	lda #$00
	sta $8000 ; Load CHR-ROM bank 0
	jmp $c000 ; Go back to the original reset routine

str_press:
	.db "PRESS ANY BUTTON TO CONTINUE",0

pal_data:
	.db $02,$30,$30,$30
	.db $02,$30,$30,$30
	.db $02,$30,$30,$30
	.db $02,$30,$30,$30

; Clear screen
clear_screen:
	lda #$20
	sta $2006	
	lda #$00
	sta $2006
	ldy #$04
-	ldx #$FF
	lda #$ff
--	sta $2007
	dex
	bne --
	dey
	bne -
	rts

.END
--------------------

+-------------+
| Is that it? |
+-------------+

Indeed. I will cover a more complicated mapper for the final NES rom expansion document.

+----------+
| Mini-FAQ |
+----------+

Q: Where do I get x816?
A: http://www.google.com/search?q=x816+assembler+download

Q: x816 doesn't work on XP!
A: It does work, you'll just have to assign more memory to it. Right click the program's icon and press 'p'. This will bring up the properties dialog for that program. Click on the 'Memory' tab and set everything to the max. A .pif shortcut will be created, leave it there.

Q: What's $nnnn for?
A: discworld.esper.net #consoledev